/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package traffic.light.simulator.town.unity;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import traffic.light.simulator.town.trafficLight.HybridTrafficLight;
import traffic.light.simulator.town.trafficLight.ITimesTrafficLight;
import traffic.light.simulator.town.trafficLight.PedestrianTrafficLight;
import traffic.light.simulator.town.trafficLight.TimesTrafficLight;
import traffic.light.simulator.town.trafficLight.TrafficLight;
import traffic.light.simulator.util.Position;

/**
 *
 *
 */
public abstract class TownUnity {

    public static final int NB_OF_TOWN_ELEMENT = 6;
    protected TownElement[][] townElements;
    protected boolean isAccessibleForMovableEntities;
    protected TownElement accessibleTownElement;
    protected int positionX;
    protected int positionY;
    protected int townSize;
    private CrossRoadType crossRoadType;
    private TrafficLight TL;
    private Thread thread;

    /**
     * @param type : the type of the town unity
     * @param positionX : the indice x where the town unity is stored on the town
     * @param positionY : the indice y where the town unity is stored on the town
     * @param townSize : the size of the town
     */
    public TownUnity(CrossRoadType type, int positionX, int positionY, int townSize) {
        this.crossRoadType = type;
        this.positionX = positionX;
        this.positionY = positionY;
        this.townSize = townSize;
        this.townElements = new TownElement[NB_OF_TOWN_ELEMENT][NB_OF_TOWN_ELEMENT];
        this.accessibleTownElement = null;
        this.isAccessibleForMovableEntities = false;

        initTL();
    }

    /**
     * Init the traffic light in the town unity
     */
    private void initTL() {
        switch (this.crossRoadType) {
            case TYPE_3:
            case TYPE_4:
                this.TL = new PedestrianTrafficLight(positionX, positionY, crossRoadType);
                break;
            case TYPE_0:
            case TYPE_1:
            case TYPE_2:
            case TYPE_5:
            case TYPE_6:
                if (new Random().nextInt(2) == 0) {
                    this.TL = new HybridTrafficLight(positionX, positionY, this.crossRoadType);
                } else {
                    this.TL = new TimesTrafficLight(positionX, positionY, this.crossRoadType);

                }
                break;
        }
    }

    /**
     * @return the dimension of the town unity
     */
    public static Dimension getSize() {
        return new Dimension(NB_OF_TOWN_ELEMENT * TownElement.getSize(), NB_OF_TOWN_ELEMENT * TownElement.getSize());
    }

    /**
     * @return boolean : true if the town unity is accessible for cars
     */
    public boolean isAccessibleForMovableEntities() {
        return isAccessibleForMovableEntities;
    }

    /**
     * Start the thread and runs the traffic light
     */
    public void run() {
        if (this.TL instanceof HybridTrafficLight || this.TL instanceof TimesTrafficLight) {
            this.thread = new Thread((ITimesTrafficLight) this.TL);
            this.thread.start();
        }
    }

    /**
     * Put the traffic light in pause
     */
    public void pause() {
        if (this.TL instanceof HybridTrafficLight || this.TL instanceof TimesTrafficLight) {
            ((ITimesTrafficLight)this.TL).setTime(false);
        }
    }

    /**
     * Restart the traffic light
     */
    public void restart() {
        if (this.TL instanceof HybridTrafficLight || this.TL instanceof TimesTrafficLight) {
            ((ITimesTrafficLight)this.TL).setTime(true);
        }
    }

    /**
     * returns the absolute x position in Y considering the i which is relative
     * @param i : the relative position in the town unity
     * @return the absolute x position
     */
    protected int absoluteElementXPosition(int i) {
        return this.positionX * TownUnity.getSize().width + i * TownElement.getSize();
    }

    /**
     * returns the absolute y position in Y considering the i which is relative
     * @param  i : the relative position in the town unity
     * @return the absolute y position
     */
    protected int absoluteElementYPosition(int i) {
        return this.positionY * TownUnity.getSize().height + i * TownElement.getSize();
    }

    public void draw(Graphics g, boolean editionMode) {
        for (int i = 0; i < NB_OF_TOWN_ELEMENT; ++i) {
            for (int j = 0; j < NB_OF_TOWN_ELEMENT; ++j) {
                townElements[i][j].draw(g, editionMode);
            }
        }
        if (TL != null) {
            this.TL.draw(g);
        }
        if (editionMode) {
            g.setColor(new Color(66, 67, 71));
            g.drawRect(positionX * getSize().width,
                    positionY * getSize().height,
                    getSize().width,
                    getSize().height);
        }
    }

    /**
     * return the town element at the position absolute position p
     * @param Position : the position (absolute)
     * @return the correspondant town element
     */
    public TownElement getTownElementAt(Position p) {
        TownElement te = null;

        for (int i = 0; i < NB_OF_TOWN_ELEMENT; ++i) {
            for (int j = 0; j < NB_OF_TOWN_ELEMENT; ++j) {
                if (p.getX() >= townElements[i][j].getAbsX()
                        && p.getY() >= townElements[i][j].getAbsY()
                        && p.getX() <= townElements[i][j].getAbsX() + getSize().width
                        && p.getY() <= townElements[i][j].getAbsY() + getSize().height) {
                    te = townElements[i][j];
                }
            }
        }

        return te;
    }

    /**
     * @return the accessible town element of the town unity
     */
    public TownElement getAccessibleTownElement() {
        if (accessibleTownElement instanceof RoadElement && ((RoadElement) accessibleTownElement).isFree()) {
            return accessibleTownElement;
        }
        return null;
    }

    /**
     * generate the unity considering the cross-road type
     */
    public void generateCorrespondantUnity() {
        for (int i = 0; i < NB_OF_TOWN_ELEMENT; ++i) {
            for (int j = 0; j < NB_OF_TOWN_ELEMENT; j++) {
                townElements[i][j] = new GrassElement(absoluteElementXPosition(j), absoluteElementYPosition(i));
            }
        }
    }

    /**
     * generate the traffic lights considerng the crossroad type
     */
    protected void generateTL() {
        if (this.crossRoadType != CrossRoadType.TYPE_11) {
            if (townElements[1][2] instanceof RoadElement) {
                ((RoadElement) townElements[1][2]).setTL(this.TL);
            }
            if (townElements[2][4] instanceof RoadElement) {
                ((RoadElement) townElements[2][4]).setTL(this.TL);
            }
            if (townElements[4][3] instanceof RoadElement) {
                ((RoadElement) townElements[4][3]).setTL(this.TL);
            }
            if (townElements[3][1] instanceof RoadElement) {
                ((RoadElement) townElements[3][1]).setTL(this.TL);
            }
        }
    }

    /*
     * returns the traffic light of the town unity
     */
    public TrafficLight getTL() {
        return TL;
    }

    /*
     * returns the cross road type
     */
    public CrossRoadType getCrossRoadType() {
        return crossRoadType;
    }

    protected abstract void generateAccessibleElements();
}
